/*
This script stores the commonly used functions
*/

/*
This cross-browser DOM routine uses feature-sensing to determine 
which DOM type is being used, and then a function to define the DOM
for a particular object based on that information
*/

//***********************************************************************//
//GLOBAL VARIABLES AND FUNCTION TO ACCESS THE DOM						 //
//***********************************************************************//

// Define global variables
var isDHTML = 0; 	// the browser supports a DOM
var isLayers = 0; 	// Netscape Layer DOM (NN4)
var isAll = 0; 		// Internet Explorer All DOM (IE4)
var isID = 0;		// WC3 ID DOM (IE5+, NN5+)
var isNS = 0;		// Nestcape browser
var isIE = 0;		// Internet Explorer browser

// Set the variables
// Note that feature sensing  doesn't work to detect 
// the Netscape Layer DOM when the code is in a separate file

isNS = (navigator.appName.indexOf('Netscape')>-1);
isIE = (navigator.appName.indexOf('Microsoft Internet Explorer')>-1);

if (document.getElementById) {isID = 1; isDHTML = 1;}
else {
	if (document.all) {isAll = 1; isDHTML = 1;}
	else {
		browserVersion = parseInt(navigator.appVersion);
		if ((navigator.appName.indexOf('Netscape') != -1) && (browserVersion == 4)) {
			isLayers = 1; isDHTML= 1;
		}
	}
}

// Function to access the DOM correctly
// It takes the ID for the desired object and accesses the DOM depending 
// on the version being used by the browser
// This version of the code takes 2 object IDs (parent and child) to accommodate nested CSS layers for Netscape 4 
// (for IE or other NS versions, only the child ID is necessary (even thought both will be supplied)). 
// If there is no nesting the parentObjectID will be null.
// Depending on the withStyle parameter, it access the style or the other 
// properties associated with the object.
function AccessDOM(parentObjectID, childObjectID, withStyle) {
	if (withStyle == 1) {
		if (isID) {return (document.getElementById(childObjectID).style);}	//W3C DOM Netscape 6 and IE 5+
		else {
			if (isAll) {return (document.all[childObjectID].style);}		//IE 4 and 5 All DOM
			else {
				if (isLayers) {
					if (parentObjectID) {									//Netscape 4 Layer DOM
						return (document.layers[parentObjectID].layers[childObjectID]);	//nested layers
					}
					else {
						return (document.layers[childObjectID]);
					}
				}
			}
		}
	}
	else {
		if (isID) {return (document.getElementById(childObjectID));}		//W3C DOM Netscape 6 and IE 5+
		else {
			if (isALL) {return(document.all[childObjectID]);}				//IE 4 and 5 All DOM
			else {
				if (isLayers) {
					if (parentObjectID) {									//Netscape 4 Layer DOM
						return (document.layers[parentObjectID].layers[childObjectID]);	//nested layers
					}
					else {
						return (document.layers[childObjectID]);
					}
				}
			}
		}
	}
}


//***************************************************************************//
//FUNCTIONS TO DETERMINE LAYER, WINDOW AND BROWSER DIMENSIONS & COORDINATES	 //
//***************************************************************************//

var screenHeight=screen.height;
var screenWidth=screen.width;
var availScreenHeight=screen.availHeight;
var availScreenWidth=screen.availWidth;
var browserBorderPixels = 6;	//for IE6
var browserMenuPixels = 26;		//for IE6
var maxClientHeight = availScreenHeight - (2 * browserBorderPixels) - browserMenuPixels;
var maxClientWidth = availScreenWidth - (2 * browserBorderPixels);

function findAvailPageHeight() {
//returns the available (i.e. inner) height of the browser window

	if(window.innerHeight!=null) 			//Netscape 4+
		return window.innerHeight;
	if(document.body.clientHeight!=null)	//Internet Explorer 4+
		return document.body.clientHeight;
	return(null);
}

function findAvailPageWidth() {
//returns the available (i.e. inner) width of the browser window

	if(window.innerWidth!=null) 			//Netscape 4+
		return window.innerWidth;
	if(document.body.clientWidth!=null)		//Internet Explorer 4+
		return document.body.clientWidth;
	return(null);
}

function findBrowserHeight(CurrWindow, AddMenus) {
//returns the height of the browser window
//this is only accurate in Netscape. A fudge is made for typical border, menus in Explorer
//the CurrWindow parameter is either passed as this or this.parent (to access the LectureWindow)
//the AddMenus parameter is used for IE, and determines whether to take into account the estimated menu & border dimensions
//this is used because screenTop (used elsewhere) is relative to the client area.

	if(CurrWindow.outerHeight!=null) 					//Browser width. Netscape 4+
		return CurrWindow.outerHeight;
	if(CurrWindow.document.body.clientHeight!=null)		//Internet Explorer 4+
	{
		if(AddMenus)
			return(CurrWindow.document.body.clientHeight + (2 * browserBorderPixels) + browserMenuPixels);
		else
			return(CurrWindow.document.body.clientHeight);			
	}
	return(null);
}

function findBrowserWidth(CurrWindow, AddMenus) {
//returns the width of the browser window
//this is only accurate in Netscape. A fudge is made for borders in Explorer
//the CurrWindow parameter is either passed as this or this.parent (to access the LectureWindow)
//the AddMenus parameter is used for IE, and determines whether to take into account the estimated border dimensions
//this is used because screenLeft (used elsewhere) is relative to the client area.

	if(CurrWindow.outerWidth!=null) 					//Browser width. Netscape 4+
		return CurrWindow.outerWidth;
	if(CurrWindow.document.body.clientWidth!=null)		//Internet Explorer 4+
	{
		if(AddMenus)
			return(CurrWindow.document.body.clientWidth + (2 * browserBorderPixels));
		else
			return(CurrWindow.document.body.clientWidth);			
	}	
	return(null);
}

function findLayerLeft(parentObjectID, childObjectID){
//returns the left position of a CSS layer object 
//include 2 params in case it's the left position of a layer inside the ContainerLayer that's required
var domStyle = AccessDOM (parentObjectID,childObjectID,1);
var dom = AccessDOM (parentObjectID,childObjectID,0);
//TEST THESE
	if(domStyle.left)				//NS 4, NS 6, IE 6 
		return parseInt(domStyle.left);	//remove the px string
	if(dom.offsetLeft)				//NS 6, IE 4 - 5.5
		return dom.offsetLeft;
	if(domStyle.pixelLeft)			//IE 4 (0r 5)?
		return domStyle.pixelLeft;
	return null;
}

function findLayerTop(parentObjectID, childObjectID){
//returns the top position of a CSS layer object 
//include 2 params in case it's the top position of a layer inside the ContainerLayer that's required
var domStyle = AccessDOM (parentObjectID,childObjectID,1);
var dom = AccessDOM (parentObjectID,childObjectID,0);

	if(domStyle.top)				//NS 4, NS 6, IE 6
		return parseInt(domStyle.top);	//remove the px string
	if(dom.offsetTop)				//NS 6, IE 4 - 5.5
		return dom.offsetTop;
	if(domStyle.pixelTop)			//IE 4 (& 5)?
		return domStyle.pixelTop;
	return null;
}

function findLayerWidth(parentObjectID, childObjectID){
//returns the width of a CSS layer object 
//include 2 params in case it's the width of a layer inside the ContainerLayer that's required
var domStyle = AccessDOM (parentObjectID,childObjectID,1);
var dom = AccessDOM (parentObjectID,childObjectID,0);

	if(domStyle.width)				//NS 4, IE 6 
		return parseInt(domStyle.width);//remove the px string
	if(domStyle.pixelWidth)			//IE 4 & 5?
		return domStyle.pixelWidth;
	if(dom.offsetWidth)				//NS 6, IE 4+
		return dom.offsetWidth;
	return null;
}

function findLayerHeight(parentObjectID, childObjectID){
//returns the height of a CSS layer object 
//include 2 params in case it's the height of a layer inside the ContainerLayer that's required
var domStyle = AccessDOM (parentObjectID,childObjectID,1);
var dom = AccessDOM (parentObjectID,childObjectID,0);

	if(domStyle.height)				//NS 4, IE 6
		return parseInt(domStyle.height);	//remove the px string
	if(dom.pixelHeight)				//IE 4 & 5?
		return dom.pixelHeight;
	if(domStyle.offsetHeight)		//NS 6, IE 4 - 5.5
		return domStyle.offsetHeight;
	return null;
}

function findXCoordInDocument(e,relScrollPage){
//returns the x coord of the mouse pointer when event e occurred
//relative to the visible document area in the browser window if not relScrollPage
//or taking into account scrolling to identify a specific region in the page.
var XCoord=0;
	
	if(e.clientX)				//IE 4+, NS 6 (relative to the window)
		XCoord = e.clientX;
	else if(e.pageX)			//NS 4 (NS 6 has this too, but it is relative to the document not the window)
		XCoord = e.pageX;

	if(relScrollPage)			//relative to the (scrolled) document
	{
		if(isNS)						//NS 
			return e.pageX;
		else if(document.body.scrollLeft)	//IE 4+
			return (XCoord + document.body.scrollLeft);
		else		
			return(XCoord);
	}
	else						//relative to the window 
		return XCoord;
}

function findYCoordInDocument(e,relScrollPage){
//returns the y coord of the mouse pointer when event e occurred
//relative to the visible document area in the browser window if not relScrollPage
//or taking into account scrolling to identify a specific region in the page.
var YCoord=0;
	
	if(e.clientY)				//IE 4+, NS 6 (relative to the window)
		YCoord = e.clientY;
	else if(e.pageY)			//NS 4 (NS 6 has this too, but it is relative to the document not the window)
		YCoord = e.pageY;

	if(relScrollPage)			//relative to the (scrolled) document
	{
		if(isNS)						//NS 
			return e.pageY;
		else if(document.body.scrollTop)	//IE 4+
			return (YCoord + document.body.scrollTop);
		else		
			return YCoord;
	}
	else						//relative to the window 
		return YCoord;
}

function findXCoordInElement(e, currTarget){
//returns the x coordinate of the mouse pointer when event e occurred, relative to the target of the event

	if(e.offsetX)				//IE 4+		
		return e.offsetX;
	else if(e.pageX)//NS 6+
		return(e.pageX - currTarget.offsetLeft - document.body.offsetLeft - findLayerLeft('','ContentLayer')); //subtract the coord of target and it's context (body) from the pageX (scrolled document) value
	else if(e.layerX)			//NS 4
		return e.layerX;
}

function findYCoordInElement(e, currTarget){
//returns the y coordinate of the mouse pointer when event e occurred, relative to the target of the event

	if(e.offsetY)				//IE 4+
		return e.offsetY;
	else if(e.pageY)	//NS 6
		return(e.pageY - currTarget.offsetTop - document.body.offsetTop + findLayerTop('','ContentLayer')); //subtract the coord of target and it's context (body) from the pageX (scrolled document) value
	else if(e.layerY)			//NS 4
		return e.layerY;
}


//***********************************************************************//
//FUNCTIONS TO CHANGE PROPERTIES										 //
//***********************************************************************//

function ChangeStyle(parentObjectID,childObjectID,styleName,newVal){
//changes a style property of a CSS layer object 
//include 2 object params in case it's the style of a layer inside the ContainerLayer that's required

try {	
	var domStyle = AccessDOM(parentObjectID, childObjectID,1);

	domStyle[styleName] = newVal;
	}
catch(exception)
	{

	}
}

function toggleVisibility(parentObjectID,childObjectID, state) {
//checks the current visibility of an object and toggles it to the opposite
var domStyle = AccessDOM(parentObjectID, childObjectID,1);
var state = domStyle.visibility;

	if(state == 'hidden' || state == 'hide')	//NS 4 uses hide and show, though can accept hidden and visible as input
		domStyle.visibility = 'visible';
	else {
		if(state =='visible' || state == 'show')
			domStyle.visibility = 'hidden';			
		else dom.visibility = 'visible';
	}
}

function MoveObjectTo(parentObjectID, childObjectID, x, y, hide){
//Moves an object to the specified coordinates
//hide is set if the object is to reappear, or is false if it is to be seen moving

	if(hide) 
		ChangeStyle(parentObjectID,childObjectID,'visibility','hidden');
	ChangeStyle(parentObjectID,childObjectID,'left',x);
	ChangeStyle(parentObjectID,childObjectID,'top',y);
	ChangeStyle(parentObjectID,childObjectID,'visibility','visible');
}


//***********************************************************************//
//FUNCTIONS TO OPEN BROWSER WINDOWS										 //
//***********************************************************************//

function MM_openBrWindow(theURL,winName,features) { //v2.0
//height and width features specify the content area
    return window.open(theURL,winName,features);
}

function OpenWindowCentralToScreen(page,name,Width,Height,features){
//opens a new window positioned centrally in the screen.
//Note the Width and Height specify the client area
//features contains a string of the pre-requisite features (with a terminating comma) (or empty)
var left = 0, top = 0;

   top = (availScreenHeight - (Height + (2 * browserBorderPixels) + browserMenuPixels))/2;
   left =(availScreenWidth - (Width + 2 * browserBorderPixels))/2;
   return MM_openBrWindow(page,name,features+'width='+Width+',height='+Height+',top='+top+',left='+left+',screenX='+left+',screenY='+top)
}
 
function OpenWindowCentralToLecture(page,name,Width,Height,features){
//opens a new window positioned centrally in the lecture window (the parent).
//Note the Width and Height specify the client area
//features contains a string of the pre-requisite features (with a terminating comma) (or empty)
var top = 0, left = 0;// default values
var LectureWindowHeight = 0; LectureWindowWidth = 0;

	LectureWindowHeight = findBrowserHeight(this.parent,0); //for IE, don't take menu height into account
	LectureWindowWidth = findBrowserWidth(this.parent,0);   //for IE, don't take border width into account
	
	//centre left and top relative to window
	top = (LectureWindowHeight - (Height + (2 * browserBorderPixels) + browserMenuPixels))/2;
	left = (LectureWindowWidth - (Width + 2 * browserBorderPixels))/2;
	
	//Add the offset from the edge of the screen
	if (window.screenLeft)		//IE (screenLeft etc. is relative to the client area
	{
		top = parent.window.screenTop + top;
		left = parent.window.screenLeft + left;
	}
	else if (window.screenX)	//NS (screenX etc. is relative to the outer boundary of the browser window
	{					//NB. NS insists on the window prefix
		top = parent.window.screenY + top;
		left = parent.window.screenX + left;
	}
 
	//check for the window opening so it's beyond the edge of the screen.
	if ((top + Height) > availScreenHeight)
		top = availScreenHeight - Height;
	else if (top < 0)
		top = 0;
 
	if ((left + Width) > availScreenWidth)
   		left = availScreenWidth - Width;
	else if (left < 0)
		left = 0;
	
	return MM_openBrWindow(page,name,features+'width='+Width+',height='+Height+',top='+top+',left='+left+',screenX='+left+',screenY='+top+'');	
}

function OpenWindowInLeftOfLecture(page,name,Width,Height,features){
//opens a new window positioned centrally in the lecture window
//The lecture window is the parent window
//features contains a string of the pre-requisite features (with a terminating comma) (or empty)
var top = 0, left = 0;// default values
var LectureWindowHeight = 0;

	LectureWindowHeight = findBrowserHeight(this.parent,0); //for IE, don't take menu height into account

	//centre top relative to window
	top = (LectureWindowHeight - (Height + (2 * browserBorderPixels) + browserMenuPixels))/2;
	 	
	//Add the offset from the edge of the screen
	if (window.screenLeft)		//IE (screenLeft etc. is relative to the client area
	{
		top = parent.window.screenTop + top;
		left = window.screenLeft;		
	}
	else if (window.screenX)	//NS (screenX etc. is relative to the outer boundary of the browser window
	{							//NB. NS insists on the window prefix
		top = parent.window.screenY + top;
		left = window.screenX;
	}

	//check for the window opening so it's beyond the edge of the screen.
	if ((top + Height) > screen.availHeight)
		top = availScreenHeight - Height; 
	else if (top < 0)
		top = 0;
		
	if ((left + Width) > screen.availWidth)
    	left = availScreenWidth - Width; 
	else if (left < 0)
		left = 0; 
		
	if (name=="CourseMap") {
	//open Course Map
    	if (!window.ContentMapWindow) {
		//CourseMap window not defined (not yet opened))
 			ContentMapWindow=MM_openBrWindow(page,name,features+'width='+Width+',height='+Height+',top='+top+',left='+left+',screenX='+left+',screenY='+top+'');
		}
		else if (!ContentMapWindow.closed){
		//CourseMap window is still open
			ContentMapWindow.focus();
		}
		else {
		//re-open Course Map window
			ContentMapWindow=MM_openBrWindow(page,name,features+'width='+Width+',height='+Height+',top='+top+',left='+left+',screenX='+left+',screenY='+top+'');
		}
  	}
  	else {
  	//open any other window
  		return MM_openBrWindow(page,name,features+'width='+Width+',height='+Height+',top='+top+',left='+left+',screenX='+left+',screenY='+top+'');
  	}
}

function OpenWindowInLeftOfOpenerLecture(page,name,Width,Height,features){
//opens a new window positioned centrally in the lecture window
//The lecture window is the parent window
//features contains a string of the pre-requisite features (with a terminating comma) (or empty)
var top = 0, left = 0;// default values
var LectureWindowHeight = 0;

	LectureWindowHeight = findBrowserHeight(this.opener.parent,0); //for IE, don't take menu height into account

	//centre top relative to window
	top = (LectureWindowHeight - (Height + (2 * browserBorderPixels) + browserMenuPixels))/2;
	 	
	//Add the offset from the edge of the screen
	if (window.screenLeft)		//IE (screenLeft etc. is relative to the client area
	{
		top = this.opener.parent.window.screenTop + top;
		left = this.opener.parent.window.screenLeft;		
	}
	else if (window.screenX)	//NS (screenX etc. is relative to the outer boundary of the browser window
	{							//NB. NS insists on the window prefix
		top = this.opener.parent.window.screenY + top;
		left = this.opener.parent.window.screenX;
	}

	//check for the window opening so it's beyond the edge of the screen.
	if ((top + Height) > screen.availHeight)
		top = availScreenHeight - Height; 
	else if (top < 0)
		top = 0;
		
	if ((left + Width) > screen.availWidth)
    	left = availScreenWidth - Width; 
	else if (left < 0)
		left = 0; 
		
	return MM_openBrWindow(page,name,features+'width='+Width+',height='+Height+',top='+top+',left='+left+',screenX='+left+',screenY='+top+'');
}

function OpenCentralWindowtoScreenOrGiveFocusWithNewPageIfHidden (windowID,page,name,Width,Height,features){
//opens a window central to the screen if it's not already open

	if (!windowID || windowID.closed) {
		windowID = OpenWindowCentralToScreen(page,name,Width,Height,features);
	}
	else	{
		windowID.location.href = page;
		windowID.focus();
	}
	return windowID;
}

function OpenCentralWindowOrGiveFocusIfHidden (windowID,page,name,Width,Height,features,adjustHeight){
//opens a window central to lecture if it's not already open
//Adjusts the height if Netscape
var windowClosedOrNeverOpened=(windowID==null);

	if (!windowClosedOrNeverOpened) 
		windowClosedOrNeverOpened = (windowID.closed);

	if (windowClosedOrNeverOpened) {
		if (isNS & (adjustHeight!=null)) {Height += adjustHeight;}
		windowID = OpenWindowCentralToLecture(page,name,Width,Height,features);
	}
	else
		windowID.focus();
	return windowID;
}

function OpenLeftWindowOrGiveFocusIfHidden (windowID,page,name,Width,Height,features){
//opens a window in left of lecture if it's not already open
var windowClosedOrNeverOpened=(windowID==null);

	if (!windowClosedOrNeverOpened) 
		windowClosedOrNeverOpened = (windowID.closed);	
	if (windowClosedOrNeverOpened) {
		windowID = OpenWindowInLeftOfLecture(page,name,Width,Height,features);
	}
	else	{
		windowID.focus();
	}
	return windowID;
}

function OpenWindowNearMouseClick(page,name,Width,Height, features, e){
//opens a new window (typically Glossary or Resource) positioned near the mouseclick
//it opens above or below depending on whether the click is in the bottom or top half of the screen resp.
//it opens centrally to the click horizontally.
//features contains a string of the pre-requisite features (with a terminating comma) (or empty)
var top = left = 0;// default values

	left = findXCoordInDocument(e,0);
	top = findYCoordInDocument(e,0);

	left = left - Width/2;

 	//place the window above or below the click, so the click area is still visible
 	if (top < availScreenHeight/2)
 		top = top + 25;
 	else {top = top - Height - 50;}

	//check for the window opening so it's beyond the edge of the screen.
 	if ((left + Width) > availScreenWidth){
   		left = availScreenWidth - Width - 10; }
 	else if (left < 0) {left = 0;}  

 	return MM_openBrWindow(page,name,features+'width='+Width+',height='+Height+',top='+top+',left='+left+',screenX='+left+',screenY='+top+'')
}

function CentreLayer(LayerID) {
//centres the container layer if the browser is resized 
//called from SMMModule etc. (the session menu page)
var availBrowserWidth=0;
var availBrowserHeight=0;
var newleft=0;
var newtop=0;

	availBrowserHeight = findAvailPageHeight();
	availBrowserWidth = findAvailPageWidth();

	newleft=(availBrowserWidth-findLayerWidth('',LayerID))/2;
	newtop=(availBrowserHeight-findLayerHeight('',LayerID))/2;

	//set the new layer position
	if (newleft >=0)				// new left position is in the browser area
		ChangeStyle('',LayerID,'left',newleft);
	else 
		ChangeStyle('',LayerID,'left',0);

	if (newtop >=0)					// new top left position is in the browser area
		ChangeStyle('',LayerID,'top',newtop);
	else
		ChangeStyle('',LayerID,'top',0);
}

function CentreBrowserWindowHoriz()	{
//returns the left position that the browser window should be to centre it horizontally
var WindowLeft=0;
var browserWidth=0;

	browserWidth = findBrowserWidth(this,1);
	if (availScreenWidth - browserWidth>0){
		WindowLeft = (availScreenWidth - browserWidth)/2;
	}
	return WindowLeft;
}

function CentreBrowserWindowVert()	{
//returns the top position that the browser window should be to centre it vertically
var WindowTop=0;
var browserHeight = 0;

	browserHeight = findBrowserHeight(this,1)
	
	if (availScreenHeight - browserHeight>0){
		WindowTop = (availScreenHeight - browserHeight)/2;
	}
	return WindowTop;
}

function CentreBrowserWindow(){
//centres the browser window within the screen's available space
//called on loading
var WindowLeft=0;
var WindowTop=0;

	WindowLeft = CentreBrowserWindowHoriz();
	WindowTop = CentreBrowserWindowVert();
	window.moveTo(WindowLeft,WindowTop);
	return false;
}

function CheckToDisplayReturnButton() {
//checks to see if the Return button/layer needs to be displayed
//it does if global variable ReturnSearchString isn't empty

	if (parent.ReturnSearchString!="") {
		ChangeStyle('','ReturnLayer','visibility','visible');
	}
}

function LoadLecture(href, page, title, lecturer){
//Loads the LectureWindow, passing the name of the first content page

	parent.location.href = href + '?' + page + ';' + title + ';' + lecturer;
}

function ReturnToPage() {
//returns to the page located in the search string (ignoring the initial question mark)
var href = '../LectureWindow.htm';

	parent.location.href = href + '?' + parent.ReturnSearchString;
}


//***********************************************************************//
//DREAMWEAVER GENERATED FUNCTIONS										 //
//***********************************************************************//

function MM_findObj(n, d) { //v4.0 generated by Dreamweaver
  var p,i,x;  
  if(!d) d=document; 
  if((p=n.indexOf("?"))>0&&parent.frames.length) {
    d=parent.frames[n.substring(p+1)].document; 
	n=n.substring(0,p);
  }
  if(!(x=d[n])&&d.all) 
  	x=d.all[n]; 
  for (i=0;!x&&i<d.forms.length;i++) 
  	x=d.forms[i][n];
  for(i=0;!x&&d.layers&&i<d.layers.length;i++) 
  	x=MM_findObj(n,d.layers[i].document);
  if(!x && d.getElementById) 
  	x=d.getElementById(n); 
  return x;
}

function MM_setTextOfLayer(objName,doc,newText) { //v3.0 generated by Dreamweaver
var	browserVersion = parseInt(navigator.appVersion);
		
	if ((obj=MM_findObj(objName, doc))!=null) with (obj)
		if (isNS && (browserVersion == 4)) {
			document.write(unescape(newText)); 
			document.close();
		}
    	else innerHTML = unescape(newText);
}

function MM_swapImgRestore() { //v3.0  generated by Dreamweaver
  var i,x,a=document.MM_sr; 
  
  for(i=0;a&&i<a.length&&(x=a[i])&&x.oSrc;i++)   
  	x.src=x.oSrc;
}

function MM_swapImage() { //v3.0  generated by Dreamweaver
//parameters list of sybmol names, document, swap image path repeated for multiple symbols, 
//terminated with 0 or 1 if symbols are preloaded
  var i,j=0,x,a=MM_swapImage.arguments; 

  document.MM_sr=new Array;	//to store the current image objects 
  for(i=0;i<(a.length-2);i+=3)
  	if ((x=MM_findObj(a[i]))!=null){
   		document.MM_sr[j++]=x; 
		if(!x.oSrc) 
			x.oSrc=x.src; 
		x.src=a[i+2];
	}
}

function MM_permanentlySwapImage() { //v3.0  generated by Dreamweaver
//parameters list of sybmol names, document, swap image path repeated for multiple symbols, 
//terminated with 0 or 1 if symbols are preloaded
  var i,j=0,x,a=MM_permanentlySwapImage.arguments; 

  document.MM_sr=new Array;	//to store the current image objects 
  for(i=0;i<(a.length-2);i+=3)
  	if ((x=MM_findObj(a[i]))!=null){
   		document.MM_sr[j++]=x; 
		x.src=a[i+2];
	}
}

//***********************************************************************//
//FUNCTIONS TO CONTROL MULTIPLE CHOICE QUESTION                          //
//***********************************************************************//

var selectedColor="#FF9C00";
var highlightColor="#009900";
var maintextColor="#006600";

var maxQuestionsOnPage = 10;		//the  maximum number of multiple choice questions on a screen
var maxOptionsPerQuestion = 20;		//the maximum selection options any particular question can have
var maxImagesPerOption = 10;		//the maximum number of images that are swapped in a any option
var MultipleChoiceQuestionsArray = null;	//an array of multiple choice questions on a screen accessing an array of option records for each question
var TrueFalseQuestionsArray = null;	//an array of true/false questions on a screen

function SwapMultipleImages (CurrSymbolsArray, SwapType, Preloaded) {
//swaps multiple numbers of images used for a selection option (so all images stored for SwapImgRestore to work
//SwapImage doesn't accept a comma-delineated string (or array) as it sees it as just one argument
//SwapType determines what version of the image is to be shown (and appended to the core image filename
//options are '','Hi','Selected', 'Bold', 'SelectedBold'
//Preloaded is 0 or 1
var Arguments = new Array();
var noSymbols = CurrSymbolsArray.length;
var symbol;

	for (symbol = 0; symbol < noSymbols; symbol++) {
		Arguments[2 * symbol] = CurrSymbolsArray[symbol].imageID;
		Arguments[2 * symbol + 1] = CurrSymbolsArray[symbol].imagePath + CurrSymbolsArray[symbol].graphicName + SwapType + '.gif';
	}
	switch (noSymbols) {
		case 1: MM_swapImage(Arguments[0],'',Arguments[1],Preloaded);
				break;
		case 2: MM_swapImage(Arguments[0],'',Arguments[1],Arguments[2],'',Arguments[3],Preloaded);						
				break;
		case 3:	MM_swapImage(Arguments[0],'',Arguments[1],Arguments[2],'',Arguments[3],Arguments[4],'',Arguments[5],Preloaded);
				break;
		case 4:	MM_swapImage(Arguments[0],'',Arguments[1],Arguments[2],'',Arguments[3],Arguments[4],'',Arguments[5],Arguments[6],'',Arguments[7],Preloaded);
				break;
		case 5:	MM_swapImage(Arguments[0],'',Arguments[1],Arguments[2],'',Arguments[3],Arguments[4],'',Arguments[5],Arguments[6],'',Arguments[7],Arguments[8],'',Arguments[9],Preloaded);
				break;
		case 6:	MM_swapImage(Arguments[0],'',Arguments[1],Arguments[2],'',Arguments[3],Arguments[4],'',Arguments[5],Arguments[6],'',Arguments[7],Arguments[8],'',Arguments[9],Arguments[10],'',Arguments[11],Preloaded);
				break;
		case 7:	MM_swapImage(Arguments[0],'',Arguments[1],Arguments[2],'',Arguments[3],Arguments[4],'',Arguments[5],Arguments[6],'',Arguments[7],Arguments[8],'',Arguments[9],Arguments[10],'',Arguments[11],Arguments[12],'',Arguments[13],Preloaded);
				break;
		case 8:	MM_swapImage(Arguments[0],'',Arguments[1],Arguments[2],'',Arguments[3],Arguments[4],'',Arguments[5],Arguments[6],'',Arguments[7],Arguments[8],'',Arguments[9],Arguments[10],'',Arguments[11],Arguments[12],'',Arguments[13],Arguments[14],'',Arguments[15],Preloaded);
				break;
		case 9:	MM_swapImage(Arguments[0],'',Arguments[1],Arguments[2],'',Arguments[3],Arguments[4],'',Arguments[5],Arguments[6],'',Arguments[7],Arguments[8],'',Arguments[9],Arguments[10],'',Arguments[11],Arguments[12],'',Arguments[13],Arguments[14],'',Arguments[15],Arguments[16],'',Arguments[17],Preloaded);
				break;
		case 10: MM_swapImage(Arguments[0],'',Arguments[1],Arguments[2],'',Arguments[3],Arguments[4],'',Arguments[5],Arguments[6],'',Arguments[7],Arguments[8],'',Arguments[9],Arguments[10],'',Arguments[11],Arguments[12],'',Arguments[13],Arguments[14],'',Arguments[15],Arguments[16],'',Arguments[17],Arguments[18],'',Arguments[19],Preloaded);
				break;
		default: break;
	}
}

function SymbolsObjectRec(path, imageID) {
//sets up the record of path and symbol name to be stored when swapped out

	this.imagePath = path;
	this.imageID = imageID;
	this.graphicName = imageID.substr(3); //remove the S0n prefix used to uniquely identify repetions of the same graphic
}

function SelectionOptionObjectRec (optionSelected, rightAnswer, optionSymbolsArray) {
//set up the record for an individual selection option in a multiple choice question
//stores whether it is selected or not (boolean), a correct answer or not 
//and a list of records of symbols used in the selection text (passed as an array of pairs of path and IDs)
var symbolIndex = 0, symbolNo=0; noSymbols=0;

	this.selected = optionSelected;
	this.correctAnswer = rightAnswer;
	if (optionSymbolsArray != null) {
	//no symbols are used in this multiple choice question
		noSymbols = optionSymbolsArray.length / 2;
		if (noSymbols > 0) {
		//this option has no symbols
			this.symbolsList = new Array(noSymbols - 1);
			for(symbolIndex=0; symbolIndex<optionSymbolsArray.length; symbolIndex+=2){
			//work through array of path and ID pairs
				symbolNo = symbolIndex / 2;
				this.symbolsList[symbolNo] = new SymbolsObjectRec(optionSymbolsArray[symbolIndex],optionSymbolsArray[symbolIndex + 1]);
			}	
		}
		else
			this.symbolsList = null;
	}
	else 
		this.symbolsList = null;
}

function MultipleChoiceObjectRec (noOptions, maxSelections, noCorrectAnswers, correctOptionsArray, SymbolsArray) {
//sets up the record for the current multiple choice question on a page
//Is used as part of an array of questions and for each question,
//stores how many selection options the question has, the number of options ticked, if the question has been checked,
//the maximum options that can be selected (1 if not multiple selection), the number of correct answers (may be different)
//and 2D array of symbols for each selection option indexed by option, and providing an zrray of paired path and name of each symbol used in option
var optionNo = 0;

	this.noOptions = noOptions;
	this.noOptionsTicked = 0;
	this.questionChecked = false;
	this.maximumSelections = maxSelections;
	this.noCorrectAnswers = noCorrectAnswers;
	this.Options = new Array(noOptions - 1);
	for(optionNo=0; optionNo<noOptions; optionNo++){
		if (SymbolsArray[optionNo] != null)
			this.Options[optionNo] = new SelectionOptionObjectRec(false, correctOptionsArray[optionNo], SymbolsArray[optionNo]);
		else
			this.Options[optionNo] = new SelectionOptionObjectRec(false, correctOptionsArray[optionNo], null);			
	}
}

function TrueFalseObjectRec (trueFalse) {
//sets up the record for the current true/false question on a page
//Is used as part of an array of questions and for each question, stores
//if the question has been answered, if the statement is true or false.

	this.questionChecked = false;
	this.TrueFalse = trueFalse;
}

function RolloverMultipleCheckbox(parentObjectID, QNum, OptionNum) {
//When rollover checkbox, highlight text of current selection and swap any symbols to highlighted version
//IF it isn't the currently selected answer and therefore orange!
//assumes the name of the hi version of the graphic uses the same stem as the original image
//CurrSymbolIDs is an array of the IDs of original symbols in the current question's option text

	if (MultipleChoiceQuestionsArray[QNum-1].questionChecked == false) { 
	//Check Answer button not been clicked
		if (MultipleChoiceQuestionsArray[QNum-1].Options[OptionNum-1].selected == false) {
		//Current option hasn't been selected/ticked
			ChangeStyle(parentObjectID,'Q' + QNum + 'Option' + OptionNum + 'CheckboxLayer','color',highlightColor);
			if (MultipleChoiceQuestionsArray[QNum-1].Options[OptionNum-1].symbolsList != null)
			//Current option includes symbols 
				SwapMultipleImages(MultipleChoiceQuestionsArray[QNum-1].Options[OptionNum-1].symbolsList,'Hi',0);
 		}  
	}
}

function RolloutMultipleCheckbox(parentObjectID, QNum, OptionNum){
//Restores the current text selection colour and restores any symbols in it
//IF it isn't the currently selected answer and therefore orange!

	if (MultipleChoiceQuestionsArray[QNum-1].questionChecked == false)  {
	//Check Answer button not been clicked
		if (MultipleChoiceQuestionsArray[QNum-1].Options[OptionNum-1].selected == false) {
		//Current option hasn't been selected/ticked
			ChangeStyle(parentObjectID,'Q' + QNum + 'Option' + OptionNum + 'CheckboxLayer','color', maintextColor);
			if (MultipleChoiceQuestionsArray[QNum-1].Options[OptionNum-1].symbolsList != null)
			//Current option includes symbols 
				MM_swapImgRestore();
		}		  
	}
}

function MoveTick (parentObjectID,QNum,OptionNum,SelectionTick,LabelTextPos,TickNumber) {
//Moves the relevant tick to be located in the checkbox of the current option
//QNum is the number of the question on the page, OptionNum the current option in the question
//SelectionTick is true if the tick is a selection tick, or false if a green "correct" tick, 
//in which case TickNumber is specified. TickNumber identifies the correct tick to be moved (a maximum number of noCorrectAnswers ticks are needed)
//LabelTextPos is either right or top
//Normal multiple choice div areas are 29px high, and tickHeight is 25, but graphic options, or those with text above are taller.
var left=0,top=0,tickheight=0, tickTop=0, LayerHeight=0, YOffset=4;
var TickName='';

	if (SelectionTick == true) 
		TickName = 'Q' + QNum + 'TickSelection1Layer';
	else
		TickName = 'Q' + QNum + 'Tick' + TickNumber + 'Layer';
		
	LayerHeight = findLayerHeight(parentObjectID,'Q' + QNum + 'Option' + OptionNum + 'CheckboxLayer');
	tickTop = findLayerTop(parentObjectID,'Q' + QNum + 'Option' + OptionNum + 'CheckboxLayer'); //initialise tickTop to top of layer
	if ((LabelTextPos=='right') && (LayerHeight!= 29)){
	//graphics used in text. Place tick in the middle (checkbox alignment is abs middle)
	 	tickHeight = findLayerHeight(parentObjectID,TickName);
		tickTop += (LayerHeight - tickHeight)/2;
	}
	else if(LabelTextPos=='top') {
	//checkbox at the bottom of the layer height
	 	tickHeight = findLayerHeight(parentObjectID,TickName);
		tickTop += (LayerHeight - tickHeight);
		if (isNS) tickTop += 22;	//adjust lower for Netscape
	}		
	left = findLayerLeft(parentObjectID,'Q' + QNum + 'Option' + OptionNum + 'CheckboxLayer') + 3;
	top = tickTop + YOffset;
	MoveObjectTo(parentObjectID,TickName,left,top,1);
	return null;
}

function DeSelectCurrentOption (parentObjectID,QNum,OptionNum) {
//De-selects a currently selected multiple choice question option

	ChangeStyle(parentObjectID,'Q'+QNum + 'TickSelection' + OptionNum + 'Layer','visibility','hidden');		//hide tick selection
	ChangeStyle(parentObjectID,'Q' + QNum + 'Option' + OptionNum + 'CheckboxLayer','color',maintextColor);	//set text colour to normal
	if (MultipleChoiceQuestionsArray[QNum-1].Options[OptionNum-1].symbolsList != null)
		SwapMultipleImages(MultipleChoiceQuestionsArray[QNum-1].Options[OptionNum-1].symbolsList,'',0);		//swap any images back to normal state
	MultipleChoiceQuestionsArray[QNum-1].Options[OptionNum-1].selected = false;								//deselect option
	MultipleChoiceQuestionsArray[QNum-1].noOptionsTicked--;													//decrement count of number of options ticked
}

function SelectCurrentOption (parentObjectID,QNum,OptionNum,LabelTextPos) {
//Selects a multiple choice question option

	if (MultipleChoiceQuestionsArray[QNum-1].maximumSelections == 1) 
	//only 1 selection allowed, so selectiontick has to be moved into place
		MoveTick(parentObjectID,QNum,OptionNum,true,LabelTextPos);
	else
		ChangeStyle(parentObjectID,'Q'+QNum + 'TickSelection' + OptionNum + 'Layer','visibility','visible');	//show tick selection
	ChangeStyle(parentObjectID,'Q' + QNum + 'Option' + OptionNum + 'CheckboxLayer','color',selectedColor);	//set text colour to selected
	if (MultipleChoiceQuestionsArray[QNum-1].Options[OptionNum-1].symbolsList != null)
		SwapMultipleImages(MultipleChoiceQuestionsArray[QNum-1].Options[OptionNum-1].symbolsList,'Selected',0);//swap any images to selected state
	MultipleChoiceQuestionsArray[QNum-1].Options[OptionNum-1].selected = true;								//select option
	MultipleChoiceQuestionsArray[QNum-1].noOptionsTicked++;													//increment count of number of options ticked
}

function SelectMulitpleCurrentAnswer (parentObjectID,QNum,OptionNum,LabelTextPos) {
//Used when mulitple selections in a multiple choice can be made
//When an answer is selected, by click or keypress, it toggles the associated tick. 
//A tick can only be shown though if not exceeded the max number of selections
//Shows the current answer text in orange
var option = 0;

	if (LabelTextPos==null) LabelTextPos = 'right';	//set the default value if not specified
	if(MultipleChoiceQuestionsArray[QNum-1].questionChecked == false){
	//Check Answer button not been clicked
		if(MultipleChoiceQuestionsArray[QNum-1].Options[OptionNum-1].selected)
		//Current option is selected, so deselect
			DeSelectCurrentOption(parentObjectID,QNum,OptionNum);
		else {
		//Current option is not selected, so select
			if (MultipleChoiceQuestionsArray[QNum-1].maximumSelections == 1)	{
			//single selection multiple choice. Automatically deselect any currently selected option first
				for (option=1; option <= MultipleChoiceQuestionsArray[QNum-1].noOptions; option++) {
					if (MultipleChoiceQuestionsArray[QNum-1].Options[option-1].selected)
						DeSelectCurrentOption(parentObjectID,QNum,option);
				}
			}
			if (MultipleChoiceQuestionsArray[QNum-1].noOptionsTicked < MultipleChoiceQuestionsArray[QNum-1].maximumSelections) 	//check that the option can be selected because doing so won't exceed the maximum selections that can be made
			//Not exceeded max selections
				SelectCurrentOption(parentObjectID,QNum,OptionNum,LabelTextPos);
			else
				alert("Please deselect an option before trying to select this one.");
		}
	
	}
}

function CrossAnIncorrectGuess (parentObjectID,QNum,OptionNum,CrossNumber,LabelTextPos) {
//Moves the red cross to be located in the checkbox of an incorrectly guessed answer
//QNum is the number of the question on the page
//OptionNum is the number of the option that has been incorrectly selected
//CrossNumber identifies the cross to be moved (a maximum number of maxSelections crosses are needed)
//LabelTextPos is either right or top
//Normal multiple choice div areas are 29px high, and tickHeight is 25, but graphic options are taller.
var left=0,top=0,tickheight=0, tickTop=0, LayerHeight=0, YOffset=4;
		
	LayerHeight = findLayerHeight(parentObjectID,'Q' + QNum + 'Option' + OptionNum + 'CheckboxLayer');
	tickTop = findLayerTop(parentObjectID,'Q' + QNum + 'Option' + OptionNum + 'CheckboxLayer'); //initialise tickTop to top of layer
	if ((LabelTextPos=='right') && (LayerHeight!= 29)){
	//graphics used in text. Place tick in the middle (checkbox alignment is abs middle)
	 	tickHeight = findLayerHeight(parentObjectID,'Q' + QNum + 'Cross' + CrossNumber + 'Layer');
		tickTop += (LayerHeight - tickHeight)/2;
	}
	else if(LabelTextPos=='top') {
	//checkbox at the bottom of the layer height
	 	tickHeight = findLayerHeight(parentObjectID,'Q' + QNum + 'Cross' + CrossNumber + 'Layer');
		tickTop += (LayerHeight - tickHeight);
		if (isNS) tickTop += 22;	//adjust lower for Netscape
	}		
	left = findLayerLeft(parentObjectID,'Q' + QNum + 'Option' + OptionNum + 'CheckboxLayer') + 3;
	top = tickTop + YOffset;
	MoveObjectTo(parentObjectID,'Q' + QNum + 'Cross' + CrossNumber + 'Layer',left,top,1);
	return null;
}

function CheckMultipleChoiceMultipleOptionAnswer(parentObjectID,QNum,IndividualWrongFeedback,LabelTextPos) {
//Hides the selection tick, shows the relevant feedback, displays a red cross on the associated answer if wrong, 
//and shows the green tick at the correct answer
//QNum is the number of the question on the page
//IndividualWrongFeedback specifies whether there is individual feedback for a wrong answer or if there is a standard feedback for a wrong answer
var option=0;
var QcorrectlyAnswered = true;	//assume question is correct until first wrong answer found
var numIncorrectSelections = 0;	//stores the number of incorrect crosses as they are displayed
var numCorrectAnswers = 0;		//stores the number of correct ticks as they are displayed
var numOfWrongAnswer = 0;		//used when max 1 selection and individual feedback given on wrong answer

if(MultipleChoiceQuestionsArray[QNum-1].questionChecked == false) {
//Check Answer button not been clicked
	if (LabelTextPos==null) LabelTextPos = 'right';	//set the default value if not specified
	if(MultipleChoiceQuestionsArray[QNum-1].noOptionsTicked >0) {
	//learner has attempted to answer the question
		//scroll through options, hiding all the orange selection ticks, assessing correct answer and 'disabling' check boxes
		for (option=1; option <= MultipleChoiceQuestionsArray[QNum-1].noOptions; option++) {
			if (MultipleChoiceQuestionsArray[QNum-1].Options[option-1].selected) {
			//option was selected, so hide selection tick, and check if option correct or not to show cross
				if (MultipleChoiceQuestionsArray[QNum-1].maximumSelections == 1)
					ChangeStyle(parentObjectID,'Q'+QNum + 'TickSelection1Layer','visibility','hidden');	//hide orange tick
				else
					ChangeStyle(parentObjectID,'Q'+QNum + 'TickSelection' + option + 'Layer','visibility','hidden');	//hide orange tick	
				if (MultipleChoiceQuestionsArray[QNum-1].Options[option-1].correctAnswer == false) 	{				
				//option incorrectly selected
					QcorrectlyAnswered = false;
					numIncorrectSelections++;
					numOfWrongAnswer = option;
					CrossAnIncorrectGuess(parentObjectID,QNum,option,numIncorrectSelections,LabelTextPos);
				}
			}
			if (MultipleChoiceQuestionsArray[QNum-1].Options[option-1].correctAnswer) {
			//show correct (green) tick, and show text and symbols in bold (selected or green colour depending if correctly selected)
				numCorrectAnswers++;
				MoveTick(parentObjectID,QNum,option,false,LabelTextPos,numCorrectAnswers);
				//Show the correct item text and graphics in bold
				ChangeStyle(parentObjectID,'Q' + QNum + 'Option' + option + 'CheckboxLayer','fontWeight','bold');
				if (MultipleChoiceQuestionsArray[QNum-1].Options[option-1].symbolsList != null) {
				//Store the Swapped Images (of the CheckAnswer button, to be restored when it loses focus
				//Otherwise the original versions of the Correct Answer images will be restored at that point!
					var a=document.MM_sr;
					if(MultipleChoiceQuestionsArray[QNum-1].Options[option-1].selected)
					//option correctly selected
						SwapMultipleImages(MultipleChoiceQuestionsArray[QNum-1].Options[option-1].symbolsList,'SelectedBold',0);
					else {
						SwapMultipleImages(MultipleChoiceQuestionsArray[QNum-1].Options[option-1].symbolsList,'Bold',0);
						QcorrectlyAnswered = false;
					}		
					document.MM_sr = a;
 				}		
			}				
			//Change the cursor on the checkboxes so that they don't look clickable anymore
			ChangeStyle(parentObjectID,'Q' + QNum + 'Option' + option + 'CheckboxLayer','cursor','default');	//N.B. the image is within the DIV, and therefore for NS 4 I may have to add another level to pass to the AccessDOM. cursor not implemented in NS 4
		}

		//display the feedback
		if(QcorrectlyAnswered == true) {
		//no wrong answers
			if ((MultipleChoiceQuestionsArray[QNum-1].noOptionsTicked == MultipleChoiceQuestionsArray[QNum-1].noCorrectAnswers) || (MultipleChoiceQuestionsArray[QNum-1].noOptionsTicked == MultipleChoiceQuestionsArray[QNum-1].maximumSelections))
			//100% correct either because all the correct answers ticked, or because the max num selections were ticked (if this is less).
			//show the correct answer feedback
				ChangeStyle(parentObjectID,'Q'+QNum+'CorrectAnswerFeedbackLayer','visibility','visible');
			else
			//show the partly correct answer (only necessary if can make more than 1 selection)
				ChangeStyle(parentObjectID,'Q'+QNum+'PartlyCorrectAnswerFeedbackLayer','visibility','visible');		
		}
		else {
			if (IndividualWrongFeedback == true) 
			//only valid when can make only 1 selection. shows the feedback for the actual wrong answer
				ChangeStyle(parentObjectID,'Q'+QNum+'WrongAnswer'+ numOfWrongAnswer + 'FeedbackLayer','visibility','visible');
			else						
			//show the feedback for any wrong answer. If can make more than 1 selection, allow for giving a partial wrong answer
				if (numIncorrectSelections == MultipleChoiceQuestionsArray[QNum-1].noOptionsTicked)
					ChangeStyle(parentObjectID,'Q'+QNum+'WrongAnswerFeedbackLayer','visibility','visible');
				else
					ChangeStyle(parentObjectID,'Q'+QNum+'PartlyWrongAnswerFeedbackLayer','visibility','visible');	
		}
					
		MultipleChoiceQuestionsArray[QNum-1].questionChecked = true;		//store that question has been checked
		return true;
	}
	else {
		alert("Please guess on an answer before selecting 'Check Answer'");
		MultipleChoiceQuestionsArray[QNum-1].questionChecked = false;
		return false;
	}
}
}

function CheckTrueFalseAnswer(parentObjectID,QNum,TrueOrFalseOption) {
//Hides the selection tick, shows the relevant feedback, displays a red cross on the associated answer if wrong, 
//and shows the green tick at the correct answer
//QNum is the number of the question on the page
//IndividualWrongFeedback specifies whether there is individual feedback for a wrong answer or if there is a standard feedback for a wrong answer

	if(TrueFalseQuestionsArray[QNum-1].questionChecked == false) {
	//Check question has not been answered
		if(TrueFalseQuestionsArray[QNum-1].TrueFalse == TrueOrFalseOption) 
			ChangeStyle(parentObjectID,'Q'+QNum+'CorrectAnswerFeedbackLayer','visibility','visible');
		else
			ChangeStyle(parentObjectID,'Q'+QNum+'WrongAnswerFeedbackLayer','visibility','visible');		
		
		TrueFalseQuestionsArray[QNum-1].questionChecked = true;		//store that question has been checked
		return true;
	}
}

function EnterPressed (evt) {
//returns true if the enter key is pressed
var keyCodePressed="";

	//if event obj arrives as a parameter, it continues to be available, otherwise, the window.event object is 
	//assigned if available, or the e variable is made an empty string.
	evt = (evt) ? evt : (window.event) ? window.event : "";
	if (evt) {
 		if (evt.which){	//NN4, NN6
			keyCodePressed = evt.which;
		}
		else {			//IE4+, NN6
			keyCodePressed = evt.keyCode;
		}
		
	  	if (keyCodePressed == 13) return true;
		else return false;
	}
	else return false;
}


//***********************************************************************//
//FUNCTIONS TO CONTROL HOTSPOT QUESTION                                  //
//***********************************************************************//

function HotSpotObjectRec (noHotSpots, maxTrys) {
//sets up the record for the current hotspot question on a page
//Is used as part of an array of questions and for each question,
//stores how many hotspots the question has, the number of hotspots found, if the question has been checked,
//the maximum trys to find the hotspot, the number of trys made
//and an array of hotspots storing whether they're found or not
var HotSpotNo = 0;

	this.noHotSpots = noHotSpots;
	this.noHotSpotsFound = 0;
	this.maxTrys = maxTrys;
	this.noTrys = 0;
	this.questionChecked = false;
	this.HotSpotFound = new Array(noHotSpots - 1);
	for(HotSpotNo=0; HotSpotNo<noHotSpots; HotSpotNo++){
		this.HotSpotFound [HotSpotNo] = false;			
	}
}

function CheckHotSpotAnswer(parentObjectID,QNum,HotSpotFound,WrongTryFeedback) {
//Checks a hotspot 'click'. HotSpotFound is false, or the hotspot number if one has been selected
//WrongTryFeedback specifies the text to show in an alert if HotSpotFound is false

if(HotSpotQuestionsArray[QNum-1].questionChecked == false) {
//Hotspots haven't been checked yet
	
	HotSpotQuestionsArray[QNum-1].noTrys++;	//increment the number of tries
	if (HotSpotFound!=false) {
	//a hotspot found
		if (HotSpotQuestionsArray[QNum-1].HotSpotFound[HotSpotFound - 1] == false) {
		//this hotspot hasn't already been found
			HotSpotQuestionsArray[QNum-1].noHotSpotsFound++;
			HotSpotQuestionsArray[QNum-1].HotSpotFound[HotSpotFound - 1] = true;
		}
		if (HotSpotQuestionsArray[QNum-1].noHotSpotsFound == HotSpotQuestionsArray[QNum-1].noHotSpots) {
		//all hotspots have been found
			ChangeStyle(parentObjectID,'Q' + QNum + 'CorrectAnswerFeedbackLayer','visibility','visible');
			ChangeStyle(parentObjectID,'Q' + QNum + 'ShowAnswerLayer','visibility','visible');
			HotSpotQuestionsArray[QNum-1].questionChecked = true;
		}		
	}
	else {
	//hotspot not found
		if(HotSpotQuestionsArray[QNum-1].noTrys < HotSpotQuestionsArray[QNum-1].maxTrys) 
			alert(WrongTryFeedback);
		else {
			ChangeStyle(parentObjectID,'Q' + QNum + 'WrongAnswerFeedbackLayer','visibility','visible');
			ChangeStyle(parentObjectID,'Q' + QNum + 'ShowAnswerLayer','visibility','visible');
		}
	}
}
}

//***********************************************************************//
//FUNCTIONS TO DISPLAY A HIDDEN LAYER WHEN LINK CLICKED OR ENTER PRESSED //
//***********************************************************************//

var visibleLayer='';	//stores the ID PREFIX of the current layer that is visible. To get the name of the layer adppend 'Layer', to get the name of the hotspot, append 'HotSpot'

function DisplayHiddenLayer(parentObjectID,childObjectPrefix,CurrVisibleObjectPrefix) {
//Displays a hidden layer, and makes any hotspot text that generated it bold
//If a layer has already been made visible, it hides it and sets the fontWeight of any associated hotspot text to normal
//the fontSize can't be obtained despite class of parent setting it?
//returns the prefix of the currently active hotspot
var dom;

	if(CurrVisibleObjectPrefix!=''){
		ChangeStyle(parentObjectID,CurrVisibleObjectPrefix+'Layer','visibility','hidden');
		//ChangeStyle(parentObjectID,CurrVisibleObjectPrefix+'HotSpot','fontWeight','normal');
		//ChangeStyle(parentObjectID,CurrVisibleObjectPrefix+'HotSpot','fontSize',currFontSize+'px');
		if (dom = AccessDOM(parentObjectID,CurrVisibleObjectPrefix+'ALink',0))
			//the currently visible object is associated with an ALINK. Sometimes the initially visible layer isn't.
			dom.className = 'DynamicTextLink';
	}
	ChangeStyle(parentObjectID,childObjectPrefix+'Layer','visibility','visible');
	//ChangeStyle(parentObjectID,childObjectPrefix+'HotSpot','fontWeight','bold');
	//ChangeStyle(parentObjectID,childObjectPrefix+'HotSpot','fontSize',currFontSize+2+'px');
	//ChangeStyle(parentObjectID,childObjectPrefix+'HotSpot','color','#006600');
	if (dom = AccessDOM(parentObjectID,childObjectPrefix+'ALink',0))
		dom.className = 'DynamicTextLinkCurrent';
	return childObjectPrefix;
}

var lastANum=0;			//stores the number of the last answer layer that was displayed as this may be different to the previous question that was clicked on
var currQuestionNum=0;	//stores the current question number. Necessary because of the delay in enabling the Check Answer button 
						//Otherwise there is the potential for a 'previous' button to be enabled and pressed before the current one catches up!

function SetTimer(parentObjectID,childObjectPrefix,ButtonIDSuffix,delayTime,delayAnswersArray) {
	
	if (delayAnswersArray!=null) {
		if(!delayAnswersArray[currQuestionNum-1]) {	//set the timer if no delay already
			setTimeout("EnableCurrentCheckAnswerButton('" + parentObjectID + "','" + childObjectPrefix+ "','" + ButtonIDSuffix + "')",delayTime); //setTimeout only takes a literal string as the call to the function
			delayAnswersArray[currQuestionNum-1] = true;
		}
		else	//enable Answer button immdiately
			EnableCurrentCheckAnswerButton(parentObjectID,childObjectPrefix,ButtonIDSuffix);			
	}			
	else	//set the timer if no delayAnswersArray passed
		setTimeout("EnableCheckAnswerButton('" + parentObjectID + "','" + childObjectPrefix+ "','" + ButtonIDSuffix + "')",delayTime); //setTimeout only takes a literal string as the call to the function
}

function DisplayCurrentHiddenAnswerLayerSetTimer(parentObjectID,childObjectPrefix,CurrVisibleObjectPrefix,ButtonIDSuffix,currentLinkClass,delayTime,delayAnswersArray) {
//Displays a hidden answer layer, and makes the hotspot text that generated it bold
//If a layer has already been made visible, it hides it and sets the fontWeight of it's hotspot text to normal
//Makes the disabled CheckAnswer button visible and sets the timeout to hide it and show the active button
//If delayAnswersArray has been passed, then only set the timer if not already done so for that question, otherwise, do it every time
//returns the prefix of the currently active hotspot
//currentLinkClass specifies the class used to highlight the currently active item.
var dom;

	//Hide any previous question layer, answer layer and buttons and reset the hotspot font
	if(CurrVisibleObjectPrefix!=''){
		ChangeStyle(parentObjectID,CurrVisibleObjectPrefix+'Layer','visibility','hidden'); 
		//Hide any answer layer which could be just passive text or correct/incorrect feedback
		ChangeStyle(parentObjectID,'Q'+lastANum+'CorrectAnswerFeedbackLayer','visibility','hidden');
		ChangeStyle(parentObjectID,'Q'+lastANum+'WrongAnswerFeedbackLayer','visibility','hidden');
		ChangeStyle(parentObjectID,'Answer'+lastANum+'Layer','visibility','hidden');
		ChangeStyle(parentObjectID,CurrVisibleObjectPrefix + "Disabled" + ButtonIDSuffix,'visibility','hidden');
		ChangeStyle(parentObjectID,CurrVisibleObjectPrefix + ButtonIDSuffix,'visibility','hidden');
		dom = AccessDOM(parentObjectID,CurrVisibleObjectPrefix+'ALink',0);
		dom.className = 'DynamicTextLink';
		MM_swapImgRestore();	//reset any bold images to normal
	}
	//show current answer layer and disabled answer button. Set the timer to enable the button
	ChangeStyle(parentObjectID,childObjectPrefix+'Layer','visibility','visible');
	ChangeStyle(parentObjectID,childObjectPrefix + "Disabled" + ButtonIDSuffix,'visibility','visible');
	currQuestionNum = childObjectPrefix.charAt(8);	//store this globally

	//set the timer for the current question
	SetTimer(parentObjectID,childObjectPrefix,ButtonIDSuffix,delayTime,delayAnswersArray);
			
	//set the hotspot font by changing it's class
	dom = AccessDOM(parentObjectID,childObjectPrefix+'ALink',0);
	dom.className = currentLinkClass;
	return childObjectPrefix;
}

function EnableCurrentCheckAnswerButton (parentObjectID,childObjectIDPrefix,ButtonIDSuffix) {
//Enables a CheckAnswer button that were originally disabled
//Checks that the button is now for the currently displayed question, as another could have been selected while a previous
//setTimeout is still counting down.
var currAnswerbutton;

	currAnswerbutton = childObjectIDPrefix.charAt(8);
	if (currAnswerbutton == currQuestionNum)  { 
		ChangeStyle(parentObjectID,childObjectIDPrefix + "Disabled" + ButtonIDSuffix,"visibility","hidden");
		ChangeStyle(parentObjectID,childObjectIDPrefix + ButtonIDSuffix,"visibility","visible");
	}	
}

function EnableCheckAnswerButton (parentObjectID,childObjectIDPrefix,ButtonIDSuffix) {
//Enables a CheckAnswer button that were originally disabled
	ChangeStyle(parentObjectID,childObjectIDPrefix + "Disabled" + ButtonIDSuffix,"visibility","hidden");
	ChangeStyle(parentObjectID,childObjectIDPrefix + ButtonIDSuffix,"visibility","visible");
}

function DisplayHiddenAnswerLayerSetTimer(parentObjectID,childObjectPrefix,ButtonIDSuffix,delayTime,delayAnswersArray) {
//Displays a hidden answer layer
//Makes the disabled CheckAnswer button visible and sets the timeout to hide it and show the active button
//If delayAnswersArray has been passed, then only set the timer if not already done so for that question, otherwise, do it every time
var dom;

	//show current answer layer and disabled answer button. Set the timer to enable the button
	ChangeStyle(parentObjectID,childObjectPrefix+'Layer','visibility','visible');
	ChangeStyle(parentObjectID,childObjectPrefix + "Disabled" + ButtonIDSuffix,'visibility','visible');
	currQuestionNum = childObjectPrefix.charAt(8);	//store this globally
	if (delayAnswersArray!=null) {
		if(!delayAnswersArray[currQuestionNum-1]) {	//set the timer if no delay already
			setTimeout("EnableCheckAnswerButton('" + parentObjectID + "','" + childObjectPrefix+ "','" + ButtonIDSuffix + "')",delayTime); //setTimeout only takes a literal string as the call to the function
			delayAnswersArray[currQuestionNum-1] = true;
		}
		else	//enable Answer button immdiately
			EnableCheckAnswerButton(parentObjectID,childObjectPrefix,ButtonIDSuffix);			
	}			
	else	//set the timer if no delayAnswersArray passed
		setTimeout("EnableCheckAnswerButton('" + parentObjectID + "','" + childObjectPrefix+ "','" + ButtonIDSuffix + "')",delayTime); //setTimeout only takes a literal string as the call to the function
	return childObjectPrefix;
}

function EnableCheckAnswerButton (parentObjectID,childObjectIDPrefix,ButtonIDSuffix) {
//Enables a CheckAnswer button that were originally disabled
var currAnswerbutton;

	currAnswerbutton = childObjectIDPrefix.charAt(8);
	ChangeStyle(parentObjectID,childObjectIDPrefix + "Disabled" + ButtonIDSuffix,"visibility","hidden");
	ChangeStyle(parentObjectID,childObjectIDPrefix + ButtonIDSuffix,"visibility","visible");
}


//***********************************************************************//
//DRAG AND DROP FUNCTIONS                                                //
//***********************************************************************//

//CAN I MAKE THIS KEYBOARD CONTROLLED?

var domStyle = null;	//the dragged object
var DragOffsetLeft=0, DragOffsetTop=0; //stores the offset due to the ContentLayer and where in the drag object the user clicked
var dropTargets;		//the possible targets to drop on
var NumTargets = 0;		//the number of possible targets
var MultipleDropsPerTarget = false;	//true if allow more than one object to be dropped on a target, false otherwise
var DropOnAnyTarget = true;	//true if can drop object on any target, or only on intended one
var dragObjects;		//the possible objects to drag
var NumDragObjects = 0;	//the number of draggable objects
var TotalDropped = 0;	//the number of draggable objects that have been dropped onto A target
var TotalDroppedOntoCorrectTarget = 0;	//counts the number of objects dropped onto the correct target
var CurrDragIndex = -1; //the index to the dragObjects array for the object being currently dragged

//Any images in the draggable object must have Img as part of their id
//N.B. don't embed images in other tags such as <STRONG>

function ObjectRec (targetID, targetLeft, targetTop, targetWidth, targetHeight) {
//sets up the record for the current target
//for target objects, snap determines whether drag objects are snapped into place or not, 
//snap left and top determine where to snap

	this.id = targetID;
	this.left = targetLeft;
	this.top = targetTop;
	this.right = targetLeft + targetWidth;
	this.bottom = targetTop + targetHeight;
}

function InitialiseTargets() {
//Initialises the possible valid areas to drop
//the first argument is the parentObjectID, the rest are the targetIDs
var target, dom=null, parentObjectID, targetID; 
var args = InitialiseTargets.arguments; 

	NumTargets = args.length - 1;
	dropTargets = new Array(NumTargets-1)	//to store the drop targets 
	parentObjectID = args[0];
	for(target=1; target<(args.length); target+=1){ 
		targetID = args[target];
		dom = AccessDOM(parentObjectID,targetID,0);
  		if (dom!=null){
			dropTargets[target-1] = new ObjectRec(targetID,findLayerLeft(parentObjectID, targetID),findLayerTop(parentObjectID, targetID),findLayerWidth(parentObjectID, targetID),findLayerHeight(parentObjectID, targetID));
			dropTargets[target-1].numDropped = 0;
			//initialise snap to false
			dropTargets[target-1].snap = false;
			dropTargets[target-1].snapLeft = 0;
			dropTargets[target-1].snapLeft = 0;
//			alert(dropTargets[target-1].left + ' ' + dropTargets[target-1].top + ' ' + dropTargets[target-1].right + ' ' + dropTargets[target-1].bottom);
		}
	}
}

function SetTargetSnapPosition () {
//sets the position that objects are snapped to if snapping into place is required
//the first argument is the parentObjectID, the second is true or false for snapping,
//the rest are the targetID, left and top positions of the snap area for the targets
var arg, target, parentObjectID, snap, targetID, targetPos=-1; 
var args = SetTargetSnapPosition.arguments; 

	parentObjectID = args[0];
	snap = args[1];
	if (snap) {
	//drag objects are to be snapped into place
		for(arg=2; arg<(args.length); arg+=3){ 
			targetID = args[arg];
			//find index to targetID in dropTargets 
			for(target=0; target<NumTargets; target++) {
				if (dropTargets[target].id == targetID)
					targetPos = target;
			}
			//target found in dropTargets array
  			if (targetPos>=0){
				dropTargets[targetPos].snap = true;
				dropTargets[targetPos].snapLeft = args[arg+1];
				dropTargets[targetPos].snapTop = args[arg+2];
			}
		}
	}
}

function InitialiseDragObjects() {
//Initialises the possible valid layers to drag, and their associated targets
//the first argument is the parentObjectID, the rest are the dragID and associated targetID pairs
var obj, dom=null, parentObjectID, dragID, dragNum=0; 
var args = InitialiseDragObjects.arguments; 

	NumDragObjects = (args.length - 1)/2;
	dragObjects = new Array(NumDragObjects-1)	//to store the draggable objects 
	parentObjectID = args[0];
	for(obj=1; obj<(args.length); obj+=2){ 
		dragID = args[obj];
		dom = AccessDOM(parentObjectID,dragID,0);
  		if (dom!=null){
			dragObjects[dragNum] = new ObjectRec(dragID,findLayerLeft(parentObjectID, dragID),findLayerTop(parentObjectID, dragID),findLayerWidth(parentObjectID, dragID),findLayerHeight(parentObjectID, dragID));
			dragObjects[dragNum].target = args[obj+1];
			dragObjects[dragNum].dropped = false;
			dragNum++;
		}
	}
}
function GetEventTarget (evt) {
//Returns a pointer to the source element 
//evt.srcElement for IE, evt.target for NS
var target;

	if (evt.target) {
		target = evt.target;
		if (target.nodeType == 3) // nodeType=3 is a text node. defeat Netscape bug
			target = target.parentNode;	
	}
	else if (evt.srcElement) 
		target = evt.srcElement;
	
	//target = (evt.target) ? evt.target : evt.srcElement;
	return target;
}

function PickObjectUp (parentObjectID, dragID, evt) {
//Finds the object that has been clicked on (the event),
//if it is identified as being draggable (via the dragID), then it sets it's zindex to 100
//Need to drag the DIV or SPAN layer that an image is contained in, but the image relates to the event
//(not an issue if just text is in the layer)
//Stores the relative position of the mouseclick so that dragging is smooth

var objectID="", drag, dragPos = 0, eventTarget=null, objectDraggable = true, DragOverImage = false;	


	if (isLayers) { //find object to be dragged using layers NO IDEA IF THIS WORKS
		var testObject;
		var xPos = evt.pageX;
		var yPos = evt.pageY;
		for (var i = document.layers.length; i >= 0; i--) {
			testObject = document.layers[i];
            if ((!testObject.id) || (testObject.id.indexOf(dragID) == -1 ))  {continue}
            if ( (xPos > testObject.left) && (xPos < (testObject.left + testObject.clip.width)) 
                  && (yPos > testObject.top) && (yPos < (testObject.top + testObject.clip.height)) ) {
                eventTarget = testObject;
        		if ((eventTarget == null) || (eventTarget.id== parentObjectID)) {
					objectDraggable = false;
					break;
				}
			}
        }     		
	}
	else {//find object to be dragged (a DIV or SPAN with "Drag" in the ID.
		eventTarget = GetEventTarget(evt);
		//search for the draggable object (it has the dragID ("Drag") as part of the ID)
		//user may have clicked on an image or text tag such as strong within the div
		while ((!eventTarget.id) || (eventTarget.id.indexOf(dragID) == -1)) {
			eventTarget = (eventTarget.parentNode) ? eventTarget.parentNode : eventTarget.parentElement; //NN uses parentnode, IE uses parentElement
			if ((eventTarget == null) || (eventTarget.id == parentObjectID)) {
				objectDraggable = false;
				break;
			}
		}
	}
	//alert(LevelsToDragLayer);
	if (objectDraggable) {
	//draggable object found
		objectID = eventTarget.id;
		for (drag=0; drag<NumDragObjects; drag++) {
		//find index to current object in array of draggable objects
	  		if (objectID == dragObjects[drag].id) {
				dragPos = drag;
				break;
			} 
		}	
		//if draggable object is not already dropped onto a target, access it's domStyle
		if (!dragObjects[dragPos].dropped) {
			CurrDragIndex = dragPos;
			domStyle = AccessDOM(parentObjectID,objectID,1);		
		}

	if (domStyle) {
		//store the current location of the mouse click relative to the drag layer (the event target may be an image) and any parent layer
		if (isIE) { //correct a potential IE error, pixelLeft and Top are user defined and occasionally might be wrong
			eventTarget.style.pixelLeft = eventTarget.offsetLeft;
			eventTarget.style.pixelTop = eventTarget.offsetTop;
		}
		DragOffsetLeft = findXCoordInElement(evt, eventTarget); //if layers, get event target differently
		DragOffsetTop = findYCoordInElement(evt, eventTarget);
		if (parentObjectID != '') {
		//take into account the offset of the parent layer if there is one
			DragOffsetLeft += findLayerLeft('',parentObjectID);
			DragOffsetTop += findLayerTop('',parentObjectID);	
		}
		if (GetEventTarget(evt).id.indexOf('Img') != -1) {	//drag is initiated over an image in the drag layer
			DragOverImage = true;
			if (isIE) {
			//calculate it's offset in the draglayer
				DragOffsetLeft += GetEventTarget(evt).offsetLeft;		
				DragOffsetTop += GetEventTarget(evt).offsetTop;
			}
		}
		domStyle.zIndex = 100;
		if (isAll)
			 document.selection.empty;//undoes any accidental text selection as a result of the pickup		
		return false;
	}
	else {
		domStyle = null;
		CurrDragIndex = -1;
		DragOffsetLeft = 0;
		DragOffsetTop = 0;
		return;
	}
	}
}

function DragObject (evt) {
//moves a draggable object (domStyle not null) as the learner moves the mouse

	if(domStyle) {
		if (evt.pageX) {	//NS
			domStyle.left = evt.pageX - DragOffsetLeft;
			domStyle.top = evt.pageY - DragOffsetTop;
		}
		else {//img jumps slightly
			domStyle.left = findXCoordInDocument(evt,1) - DragOffsetLeft;
			domStyle.top = findYCoordInDocument(evt,1) - DragOffsetTop;
		}
		evt.returnValue = false; //cancels any other actions associated with the event (stops the apparent selection of elements observed on my machine)
	}
}


function ObjectOverTarget(CurrX, CurrY, CurrTarget) {
//returns true if the Currx and Y values of the left and top of the dragged object 
//are within the currently tested target area
//allow a little leeway to hit the target area
//CHECK THIS WITH FITTED TARGET LAYER
var leeway = 10;

	if ((CurrX + leeway >= CurrTarget.left) && (CurrX + leeway + 30 <= CurrTarget.right) && (CurrY + leeway >= CurrTarget.top) && (CurrY <= CurrTarget.bottom)) 
		return true;
	else
		return false;
}

function DropObjectOntoTarget(parentObjectID,overTargetID,overTargetPos) {
//drops an object onto a target, snapping into place if required and giving feedback if
//it's the last one dropped
		
	//increment the total number of objects dropped and how many have been dropped over the target	
	TotalDropped++;
	dropTargets[overTargetPos].numDropped++;
	
	//snap into place if required
	if (dropTargets[overTargetPos].snap){
		domStyle.left = dropTargets[overTargetPos].snapLeft;
		domStyle.top =  dropTargets[overTargetPos].snapTop;
	}
			
	//disable the drag object - set dropped to true and change background to appear 'undraggable'  
	dragObjects[CurrDragIndex].dropped = true;
	domStyle["backgroundColor"] = "#FFFFFF";
	
	//test if object dropped onto the correct target
	if (dragObjects[CurrDragIndex].target == overTargetID)
		TotalDroppedOntoCorrectTarget++;
			
	//check if all draggable objects have been dropped and give feedback
	//only necessary if objects can be dropped on any target
	if(DropOnAnyTarget && (TotalDropped == NumDragObjects)) 
		CheckDragDropResults(parentObjectID);

}

function DropObject(parentObjectID,evt) {
//triggered when the user releases the mouse
//tests if the object of dropped over the target and drops it, or moves the dragged object back to it's original position
var CurrX, CurrY, dragObjectID = '';
var overTargetID = '', overTargetPos, target, targetForOffset;

	if(domStyle) {
	//mouseup occured over the dragged object 
		//for NS, if drag occured over text in the draglayer, find the parentNode parentNode to use as 
		//the offsetLeft in findXCoordInElement for some reason!!!
		if ((isNS) && (!evt.target.id))
			targetForOffset = evt.target.parentNode.parentNode;
		else
			targetForOffset = GetEventTarget(evt);
		CurrX = findXCoordInDocument(evt,1) - findXCoordInElement(evt, targetForOffset) - findLayerLeft('',parentObjectID);
		CurrY = findYCoordInDocument(evt,1) - findYCoordInElement(evt, targetForOffset) - findLayerTop('',parentObjectID);
		//Check if the object is dropped over one of the targets
		for(target=0; target<NumTargets; target+=1){
			if (ObjectOverTarget(CurrX, CurrY,dropTargets[target])) {		
				overTargetID = dropTargets[target].id;
				overTargetPos = target;
				break;
			}
		}
		if ((overTargetID != '') && (MultipleDropsPerTarget || (dropTargets[overTargetPos].numDropped == 0)) && (DropOnAnyTarget || (dragObjects[CurrDragIndex].target == overTargetID)))
		//over target area and either multiple drops allowed, or nothing dropped yet, and either can drop on any target or target is intended target
			DropObjectOntoTarget(parentObjectID,overTargetID,overTargetPos);
		else {
		//not dropped over a target. Return to initial position
			domStyle.left = dragObjects[CurrDragIndex].left;
			domStyle.top = dragObjects[CurrDragIndex].top;
			//selection of objects to the right needs to be undone
		}
		DragOffsetLeft = 0;
		DragOffsetTop = 0;
		CurrDragIndex = -1;
		domStyle.zIndex = 5;	
		domStyle = null;
	}
	if (isAll)	{
		document.selection.clear;//undoes any accidental text selection as a result of the pickup
	}
}

function CheckDragDropResults(parentObjectID) {
//checks the success of the drag and drop when objects can be dropped on nay target, and gives appropriate feedback
var NumWrong = 0;
	if (TotalDroppedOntoCorrectTarget == NumDragObjects) {
		ChangeStyle(parentObjectID,'CorrectAnswerFeedbackLayer','visibility','visible');
	}
	else {
		NumWrong = NumDragObjects - TotalDroppedOntoCorrectTarget;
		ChangeStyle(parentObjectID,'WrongAnswer'+NumWrong+'FeedbackLayer','visibility','visible');
	}
}

function ResetDragDrop (parentObjectID) {
//resets a drag drop - moves the draggable objects back to their initial positions
var drag, dragObjectID, domS, target;
var Wrong = 0;

	//move drag drop layers back to initial positions
	for (drag=0; drag<NumDragObjects; drag++) {
	  	dragObjectID = dragObjects[drag].id;
		domS = AccessDOM(parentObjectID,dragObjectID,1);
		domS.left = dragObjects[drag].left;
		domS.top = dragObjects[drag].top;
		//enable the drag object
		domS["backgroundColor"] = "#CCFFFF";
		dragObjects[drag].dropped = false;
	}
	//reset how many objects have landed on a target
	for (target=0; target<NumTargets; target++) 
		dropTargets[target].numDropped = 0;
			
	//hide any feedback layers
	ChangeStyle(parentObjectID,'CorrectAnswerFeedbackLayer','visibility','hidden');
	for (Wrong=2; Wrong <= NumDragObjects; Wrong++)
		ChangeStyle(parentObjectID,'WrongAnswer'+Wrong+'FeedbackLayer','visibility','hidden');
	//reset global variables
	TotalDropped = 0;
	TotalDroppedOntoCorrectTarget = 0;
	CurrDragIndex = -1;
}

function ShowDragDropAnswer (parentObjectID) {
//moves the all the draggable layers to their correct targets
var drag, dragObjectID, targetID, target, targetPos=0, domS,Wrong;

	for (drag=0; drag<NumDragObjects; drag++) {
	  	dragObjectID = dragObjects[drag].id;
		targetID = dragObjects[drag].target;
		
		//find the targetPos for the intended target
		for(target=0; target<NumTargets; target+=1){
			if (targetID == dropTargets[target].id) 
				targetPos = target;
		}

		//move the drag object onto the target
		//snap into place if required, otherwise move over target left & top
		domS = AccessDOM(parentObjectID,dragObjectID,1);
		if(dropTargets[targetPos].snap) {
			domS.left = dropTargets[targetPos].snapLeft;
			domS.top = dropTargets[targetPos].snapTop;
		}
		else {
			domS.left = dropTargets[targetPos].left;
			domS.top = dropTargets[targetPos].top;
		}
		//disable the drag object
		domS["backgroundColor"] = "#FFFFFF";
		dragObjects[drag].dropped = true;
	}
	//hide any feedback layers
	ChangeStyle(parentObjectID,'CorrectAnswerFeedbackLayer','visibility','hidden');
	for (Wrong=2; Wrong <= NumDragObjects; Wrong++)
		ChangeStyle(parentObjectID,'WrongAnswer'+Wrong+'FeedbackLayer','visibility','hidden');

}

function defaultEvents (event) {
	if (isLayers) {
		//gives Navigator 4 global event capturing
		document.captureEvents (event.MOUSEDOWN | event.MOUSEMOVE | event.MOUSEUP);
	}
	if (isDHTML) {
		document.onMouseDown = PickObjectUp();
		document.onMouseMove = DragObject();
		document.onMouseUp = DropObject()
	}
}


//***********************************************************************//
//NETSCAPE DIV IN FRAMES POSITIONING                                     //
//***********************************************************************//

function positionContentLayerinFrame (left,top,width,height) {
//positions a the ContentLayer DIV layer. In frames, Netscape positions them too low (seems to be hidden gap at the top of the frame)
//adjust for this for Netscape

	if (isNS) {top = top - 20;}
	document.write("<div id='ContentLayer' style='position:absolute; left:" + left + "px; top:" + top + "px; width:" + width+ "px; height:" + height + "px; z-index:3'>");
}

function endDIV () {
//writes the terminating DIV tag when it's been dynamically started using javascript
	document.write("</div>");
}

function positionDIVinFrame (idName,className,left,top,width,height,zindex, visibility, adjustTop, adjustLeft, adjustHeight, adjustWidth,tabindex) {
//positions a DIV layer. In frames, Netscape positions them too high 
//adjust for this for Netscape. Sometimes need to adjust the left position too.

	if (isNS & (adjustTop!=null)) {top = top + adjustTop;}
	if (isNS & (adjustLeft!=null)) {left = left + adjustLeft;}
	if (isNS & (adjustWidth!=null)) {width = width + adjustWidth;}
	if (isNS & (adjustHeight!=null)) {height = height + adjustHeight;}
	document.write("<div id='" + idName + "' class='" + className + "' tabIndex = '" + tabindex + "' style='position:absolute; left:" + left + "px; top:" + top + "px; width:" + width+ "px; height:" + height + "px; z-index:" + zindex + "; visibility:" + visibility + "'>");
}